/*
 * JGO2RDF creates a RDF representation of GAF2 files, which are automatically sourced from GO ftp site.
 * Copyright (C) 2012 Matthew M. Hindle & Artem Lysenko
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

package uk.co.jgo2rdf.goa.goa2rdf.deligates;

import com.hp.hpl.jena.rdf.model.Model;
import com.hp.hpl.jena.rdf.model.Resource;
import com.hp.hpl.jena.vocabulary.OWL;
import com.hp.hpl.jena.vocabulary.RDF;
import com.hp.hpl.jena.vocabulary.RDFS;
import org.apache.log4j.Logger;
import uk.co.jgo2rdf.exception.AccessionNonConformentException;
import uk.co.jgo2rdf.goa.deligates.EntityRDFizer;
import uk.co.jgo2rdf.goa.go.GOFactory;
import uk.co.jgo2rdf.goa.model.GOAEntry;
import uk.co.jgo2rdf.rdf.lsrn.LSRNVocab;
import uk.co.jgo2rdf.rdf.sio.SIOVocab;

import java.util.HashMap;
import java.util.Map;

/**
 * Created by IntelliJ IDEA.
 * User: mhindle
 * Date: 14/02/12
 * Time: 11:24
 * To change this template use File | Settings | File Templates.
 */
public class GenericGOAParser implements GOARDFizer {

    private static final Logger log = Logger.getLogger(GenericGOAParser.class);

    private Map<String, EntityRDFizer> rdfizers = new HashMap<String, EntityRDFizer>();

    @Override
    public void addEntityRDFizer(String database, EntityRDFizer rdfizer) {
        rdfizers.put(database.toUpperCase(), rdfizer);
    }


    public void rdfizeGOA(Model jenaModel, GOAEntry goEntry, String provider) throws Exception {
        //if its a not we don't model it at the moment...availible on request
        if (goEntry.hasQualifier()
                && goEntry.getQualifier().toUpperCase().contains("NOT"))
            return;

        String database = goEntry.getDB();
        String id = goEntry.getDBObject_ID();

        EntityRDFizer rdfizer = rdfizers.get(database.trim().toUpperCase());

        if (rdfizer == null) {
            throw new AccessionNonConformentException("Could not rdfize " + database + " database not recognised with id " + id);
        }

        Resource subject = rdfizer.rdfize(jenaModel, id);

        Resource dna = null;
        Resource rna = null;
        Resource protein = null;

        if (subject.hasProperty(RDF.type)) {
            if (subject.getProperty(RDF.type).getObject().asResource().equals(SIOVocab.dna)) {
                dna = subject;
            } else if (subject.getProperty(RDF.type).getObject().asResource().equals(SIOVocab.rna)) {
                rna = subject;
            } else if (subject.getProperty(RDF.type).getObject().asResource().equals(SIOVocab.protein)) {
                protein = subject;
            } else {
                throw new IncompatableRDFization("Rdfization of " + id + " using " + rdfizer.getClass() + " produced subject of unknown type: " + subject.getProperty(RDF.type).getObject().asResource().getURI());
            }
        } else {
            throw new IncompatableRDFization("Rdfization of " + id + " using " + rdfizer.getClass() + " produced subject of no type: ");
        }

        String uri = subject.getURI().replaceAll("(-rna|-dna|-protein)", "");

        if (rna == null && (dna != null || goEntry.getDBObjectType().contains("RNA"))) {
            rna = jenaModel.createResource(uri + "-rna", SIOVocab.rna);
            rna.addLiteral(RDFS.label, id + "-protein");
        }

        if (protein == null) {
            protein = jenaModel.createResource(uri + "-protein", SIOVocab.protein);
            protein.addLiteral(RDFS.label, id + "-protein");
        }

        if (dna != null)
            dna.addProperty(SIOVocab.is_transcribed_into, rna);

        if (rna != null)
            rna.addProperty(SIOVocab.is_translated_into, protein);

        if (goEntry.hasQualifier()
                && goEntry.getQualifier().toUpperCase().contains("NOT"))
            return;

        String goID = goEntry.getGO_ID_String().toUpperCase();

        Resource entity = jenaModel.createResource(jenaModel.createResource(GOFactory.getGoUri(goID) + "_goa"));

        Resource go_record = jenaModel.createResource(GOFactory.getGoUri(goID), LSRNVocab.GO_Record);
        Resource go_identifier = jenaModel.createResource(GOFactory.getGoUri(goID) + "-identifier");
        go_identifier.addLiteral(SIOVocab.has_value, goID);
        go_record.addProperty(SIOVocab.has_unique_identifier_attribute, go_identifier);
        go_record.addLiteral(RDFS.label, goID);
        go_record.addProperty(OWL.sameAs, jenaModel.createResource(GOFactory.getOldGoUri(goID), LSRNVocab.GO_Record));

        entity.addProperty(SIOVocab.is_subject_of, go_record);

        Resource ecURI = jenaModel.createResource(
                "http://purl.org/obo/owl/GO#GO_" + goEntry.getEvidenceCode().trim());

        Resource evidence = jenaModel.createResource(ecURI);
        evidence.addLiteral(RDFS.label, goEntry.getEvidenceCode());
        evidence.addLiteral(SIOVocab.has_provider, provider);

        entity.addProperty(SIOVocab.has_supporting_evidence, evidence);
        log.debug("Added " + goEntry.getEvidenceCode() + " as evidence to " + entity.getURI());

        String type = goEntry.getDBObjectType();
        if (type.toUpperCase().contains("RNA")) {
            rna.addProperty(SIOVocab.is_subject_of, entity);
        } else {
            protein.addProperty(SIOVocab.is_subject_of, entity);
        }
    }

}
